/*
 *  Cero Project - Copyright   2006 The Cero Developement Team 
 *  (Michael Laguerre, Camille Roux, Matthieu Segret, Mathieu Sivade) 
 * 
 *  This program is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU General Public License as published by the Free 
 *  Software Foundation; either version 2 of the License, or (at your option) 
 *  any later version.
 * 
 *  This program is distributed in the hope that it will be useful, but 
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 *  for more details.
 */

package org.ceroproject.plugin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.ceroproject.games.AIPlayer;
import org.ceroproject.games.Game;
import org.ceroproject.games.GameInitializer;
import org.ceroproject.games.Player;
import org.ceroproject.games.Rule;


class GamePlugin extends AbstractPlugin implements Plugin {

	private Class<? extends Game> gameType;

	private Game dumbInstance;

	private Collection<Class<? extends Rule>> rules = new HashSet<Class<? extends Rule>>();

	private Collection<Class<? extends GameInitializer>> initializers = new HashSet<Class<? extends GameInitializer>>();

	// the normal player is referenced by null
	private Map<String, Class<? extends Player>> playersType = new HashMap<String, Class<? extends Player>>();

	public GamePlugin(Class<? extends Game> gameClass)
			throws NotInstantiableException {
		gameType = gameClass;
		dumbInstance = (Game) tryInstanciante(gameType);
	}

	public String getPluginName() {
		return dumbInstance.getGameName();
	}

	public Game newGameInstance() {
		try {
			return (Game) tryInstanciante(gameType);
		} catch (Exception e) {
			// the class should be available, as it has been instanciated once
			// before
			e.printStackTrace();
		}
		return null;
	}

	public Collection<Rule> getRules() {
		Collection<Rule> result = new ArrayList<Rule>();
		for (Class<? extends Rule> ruleType : rules) {
			try {
				result.add((Rule) tryInstanciante(ruleType));
			} catch (Exception e) {
				// the class should be available, as it has been instanciated
				// once before
				e.printStackTrace();
			}
		}
		return result;
	}

	void addRule(Class<? extends Rule> ruleClass)
			throws NotInstantiableException {
		tryInstanciante(ruleClass);
		rules.add(ruleClass);
	}

	public Collection<GameInitializer> getInitializers() {
		Collection<GameInitializer> result = new ArrayList<GameInitializer>();
		for (Class<? extends GameInitializer> initName : initializers) {
			try {
				result.add((GameInitializer) tryInstanciante(initName));
			} catch (Exception e) {
				// the class should be available, as it has been instanciated
				// once before
				e.printStackTrace();
			}
		}
		return result;
	}

	void addInitializer(Class<? extends GameInitializer> initializerType)
			throws NotInstantiableException {
		tryInstanciante(initializerType);
		initializers.add(initializerType);
	}

	public Player newPlayer() {
		try {
			return (Player) tryInstanciante(playersType.get(null));
		} catch (Exception e) {
			// the class should be available, as it has been instanciated once
			// before
			e.printStackTrace();
		}
		return null;
	}

	public AIPlayer newAIPlayer(String aiName) {
		try {
			return (AIPlayer) tryInstanciante(playersType.get(aiName));
		} catch (Exception e) {
			// the class should be available, as it has been instanciated once
			// before
			e.printStackTrace();
		}
		return null;
	}

	void setPlayerType(Class<? extends Player> playerType)
			throws NotInstantiableException {
		tryInstanciante(playerType);
		playersType.put(null, playerType);
	}

	void addAIType(Class<? extends AIPlayer> aiClass) throws NotInstantiableException {
		AIPlayer aip = (AIPlayer) tryInstanciante(aiClass);
		playersType.put(aip.getAIName(), aiClass);
	}

	public Collection<String> getAINames() {
		Collection<String> ainames = new ArrayList<String>(playersType.keySet());
		ainames.remove(null);
		return ainames;
	}

	Class getGameType() {
		return gameType;
	}

}
